/**
 * Created by jinxs on 14-8-19.
 */
(function ($) {
    /**
     * 缓存名称
     * @type {string}
     * @private
     */
    var _cacheName = 'uiCombobox';
    /**
     * @class 下拉框
     * @extends uiCombo
     * @requires {@link uiCombo}
     * @constructor uiCombobox
     * @summary 构造函数
     * @param [options] {Object|String} 组件配置参数|要调用的组件方法名
     * @param [param] {Object} 表示要调用的组件方法的参数
     * @example
     * // 构件组件
     * $('#selectAge').uiCombobox({direction: 'left'});
     * // 调用组件方法options
     * $('#selectAge').uiCombobox("options");
     */
    $.fn.uiCombobox = function (options, param) {
        if (typeof options == 'string') {
            var method = $.fn.uiCombobox.methods[options];
            if (method) {
                return method(this, param);
            } else {
                return this.uiCombo(options, param);
            }
        }
        return this.each(function () {
            var me = $(this);
            var state = me.data(_cacheName);

            options = options || {};
            if (state) {
                $.extend(state.options, options);
                _init(me);
            } else {
                state = {
                    options: $.extend({}, $.fn.uiCombobox.defaults, me.parseUIConfig(), options),
                    data: []
                };
                me.data(_cacheName, state);
                _init(me);
                var data = _parseData(me);
                if (data.length) {
                    _loadData(me, data);
                }
            }
            if (state.options.data) {
                _loadData(me, state.options.data);
            }
            _request(me);
        });
    };

    /**
     * 方法
     * @lends uiCombobox.prototype
     */
    $.fn.uiCombobox.methods = {
        /**
         * @summary 获得组件的配置副本对象
         * @name uiCombobox#options
         * @function
         * @returns {Object} 组件的配置副本对象
         */
        options: function (target) {
            var copts = target.uiCombo('options');
            return $.extend($.data(target[0], _cacheName).options, {
                originalValue: copts.originalValue,
                disabled: copts.disabled,
                readonly: copts.readonly
            });
        },
        /**
         * @summary 获得组件的数据对象
         * @name uiCombobox#getData
         * @function
         * @returns {Array<Object>} 组件的数据对象
         * @example
         * var option = #("selectAge").uiCombobox("options");
         * var data = #("selectAge").uiCombobox("getData");
         * var age = data[0][option.textField];
         * alert(age > 28);
         */
        getData: function (target) {
            return $.data(target[0], _cacheName).data;
        },
        /**
         * @summary 设置组件的值
         * @name uiCombobox#setValues
         * @function
         * @param values {Array<String>} 组件的值列表
         * @returns {jQuery} 组件对象
         */
        setValues: function (target, values) {
            _setValues(target, values);
            return target;
        },
        /**
         * @summary 设置组件的值
         * @name uiCombobox#setValue
         * @function
         * @param value {String} 要设置的值
         * @returns {jQuery} 组件对象
         */
        setValue: function (target, value) {
            _setValues(target, [value]);
            return target;
        },
        /**
         * @summary 清除组件的已选值
         * @name uiCombobox#clear
         * @function
         */
        clear: function (target) {
            target.uiCombo('clear');
            var panel = target.uiCombo('panel');
            panel.find('div.ui_combobox-item-selected').removeClass('ui_combobox-item-selected');
        },
        /**
         * @summary 重置组件的值
         * @name uiCombobox#reset
         * @function
         * @returns {jQuery} 组件对象
         */
        reset: function (target) {
            var opts = target.uiCombobox('options');
            if (opts.multiple) {
                target.uiCombobox('setValues', opts.originalValue);
            } else {
                target.uiCombobox('setValue', opts.originalValue);
            }
            return target;
        },
        /**
         * @summary 加载组件的选项列表
         * @name uiCombobox#loadData
         * @function
         * @param data {Array<String>} 组件的值列表
         * @returns {jQuery} 组件对象
         * @example
         * var box = #("selectAge").uiCombobox({
         *   multiple:true
         * });
         * var data=[{text:'young',value:18},{text:'old',value:48}];
         * box.uiCombobox("loadData", data);
         */
        loadData: function (target, data) {
            _loadData(target, data);
            return target;
        },
        /**
         * 若不指定url的值，将使用配置对象的url
         * @summary 根据数据地址加载组件的选项列表
         * @name uiCombobox#reload
         * @function
         * @param [url] {String} 数据地址
         * @returns {jQuery} 组件对象
         */
        reload: function (target, url) {
            _request(target, url);
            return target;
        },
        /**
         * @summary 设置组件的选择值
         * @name uiCombobox#select
         * @function
         * @param value {String} 要选择的值
         * @returns {jQuery} 组件对象
         */
        select: function (target, value) {
            _select(target, value);
            return target;
        },
        /**
         * @summary 取消设置组件的选择值
         * @name uiCombobox#unselect
         * @function
         * @param value {String} 要取消选择的值
         * @returns {jQuery} 组件对象
         */
        unselect: function (target, value) {
            _unselect(target, value);
            return target;
        },
        /**
         * @summary 通过Value获取行索引
         * @name uiCombobox#getRowIndex
         * @function
         * @param value {String} value值
         * @returns {jQuery} 组件对象
         */
        getRowIndex: function (target, value) {
            return _getRowIndex(target, value);
        }
    };
    $.fn.uiCombobox.defaults = $.extend({}, $.fn.uiCombo.defaults,
        /**
         * 默认配置
         * @lends uiCombobox.prototype
         */
        {
            /**
             * @type String
             * @default "value"
             * @summary 组件数据"值"字段
             */
            valueField: 'value',
            /**
             * @type String
             * @default "text"
             * @summary 组件数据"文本"字段
             */
            textField: 'text',
            /**
             * @type String
             * @default null
             * @summary 组件数据"组"字段
             */
            groupField: null,
            /**
             * @type Function
             * @name uiCombobox#groupFormatter
             * @param group {String} 分组的值
             * @default 默认不转换
             * @summary 将分组值转换为显示文本方法
             */
            groupFormatter: function (group) {
                return group;
            },
            /**
             * @type String
             * @default null
             * @summary 默认空值
             */
            nullValue: null,
            /**
             * 可选值有local（使用本地数据）,remote（根据给定的URL加载）
             * @type String
             * @default "local"
             * @summary 组件数据加载模式
             */
            mode: 'local',
            /**
             * 可选值有get, post
             * @type String
             * @default "post"
             * @summary 向指定的url请求数据时使用的方法
             */
            method: 'post',
            /**
             * 可选值有get, post
             * @type String
             * @default null
             * @summary 指定远程数据加载的url
             */
            url: null,
            /**
             * 可选值有get, post
             * @type Array<Object>
             * @default null
             * @summary 指定组件的本地数据
             */
            data: null,
            /**
             * @type Number
             * @default 0
             * @summary 组件输入框在编辑事当大于等于queryMin执行查询
             */
            queryMin: 0,
            /**
             * 每个事件方法的this指向组件jQuery对象，事件可包含：<br/><br/>
             * <TABLE cellSpacing="1" width="100%" class="params">
             * <TR>
             * <TH width="12%">事件</TH>
             * <TH width="88%">说明</TH></TR>
             * <TR><TD align=center>up</TD><TD>键盘上方向键按下时触发，方法包含一个参数e(事件对象)</TD></TR>
             * <TR><TD align=center>down</TD><TD>键盘下方向键按下时触发，方法包含一个参数e(事件对象)</TD></TR>
             * <TR><TD align=center>left</TD><TD>键盘左方向键按下时触发，方法包含一个参数e(事件对象)</TD></TR>
             * <TR><TD align=center>right</TD><TD>键盘右方向键按下时触发，方法包含一个参数e(事件对象)</TD></TR>
             * <TR><TD align=center>enter</TD><TD>键盘回车键按下时触发，方法包含一个参数e(事件对象)</TD></TR>
             * <TR><TD align=center>query</TD><TD>执行查询时时触发，方法包含两个参数val, e(组件输入框的值，事件对象)</TD></TR>
             * </TABLE>
             * @summary 在组件输入框有键盘事件时触发的一系列方法。
             * @name uiCombobox#keyHandler
             * @default {}
             */
            keyHandler: {
                up: function (e) {
                    _nav(this, 'prev');
                    e.preventDefault()
                },
                down: function (e) {
                    _nav(this, 'next');
                    e.preventDefault()
                },
                left: function (e) {
                },
                right: function (e) {
                },
                enter: function (e) {
                    _doEnter(this)
                },
                query: function (input, e) {
                    _doQuery(this, input)
                }
            },
            /**
             * 返回true表示row所表示的值满足查询
             * @type Function
             * @name uiCombobox#filter
             * @param input {String} 组件输入框的值
             * @param row {Object} 组件数据对象，如{text:'young',value:18}
             * @default 见示例
             * @summary 组件执行查询时的数据筛选方法
             * @example
             * var box = #("selectAge").uiCombobox({
        *   multiple:true,
        *   filter:function (input, row) {
        *     var opts = $(this).uiCombobox('options');
        *     return row[opts.textField].toLowerCase().indexOf(input.toLowerCase()) > -1;
        *   }
        * });
             */
            filter: function (input, row) {
                var opts = $(this).uiCombobox('options');
                return row[opts.textField].toLowerCase().indexOf(input.toLowerCase()) > -1;
            },
            /**
             * @type Function
             * @name uiCombobox#formatter
             * @param row {Object} 组件数据对象，如{text:'young',value:18}
             * @default 见示例
             * @summary 根据组件数据对象设置显示文本方法
             * @example
             * var box = #("selectAge").uiCombobox({
        *   multiple:true,
        *   formatter:function (row) {
        *      var opts = $(this).uiCombobox('options');
        *      return row[opts.textField];
        *   }
        * });
             */
            formatter: function (row) {
                var opts = $(this).uiCombobox('options');
                return row[opts.textField];
            },
            /**
             * @type Function
             * @name uiCombobox#loader
             * @param param {String} 数据请求参数
             * @param success {Function} 数据请求成功执行的方法
             * @param error {Function} 数据请求失败执行的方法
             * @default 见示例
             * @summary 设置组件数据加载的方法
             * @example
             * var box = #("selectAge").uiCombobox({
        *   multiple:true,
        *   loader:function (param, success, error) {
        *      var opts = $(this).uiCombobox('options');
        *      if (!opts.url) return false;
        *      $.ajax({
        *          type: opts.method,
        *          url: opts.url,
        *          data: param,
        *          dataType: 'json',
        *          success: function (data) {
        *              success(data);
        *          },
        *          error: function () {
        *              error.apply(this, arguments);
        *          }
        *      });
        *   }
        * });
             */
            loader: function (param, success, error) {
                var opts = $(this).uiCombobox('options');
                if (!opts.url) return false;
                $.ajax({
                    type: opts.method,
                    url: opts.url,
                    data: param,
                    showAlert: false,
                    dataType: 'json',
                    success: function (result) {
                        if (result.success) {
                            success(result.data);
                        }
                    },
                    error: function () {
                        error.apply(this, arguments);
                    }
                });
            },
            /**
             * @type Function
             * @name uiCombobox#loadFilter
             * @param data {Array<Object>} 数据对象列表
             * @default 默认不筛选
             * @summary 数据加载时进行筛选的方法
             */
            loadFilter: function (data) {
                return data;
            },
            /**
             * 可包含getEl和getRow两个方法
             * @summary 设置组件查找页面选项元素和选项数据的方法
             * @type Object
             * @name uiCombobox#finder
             * @default 见源码
             */
            finder: {
                /**
                 * TODO: how to describe this kind of properties
                 * @type Function
                 * @name uiCombobox#finder.getEl
                 * @param target {jQuery} 组件对象
                 * @param value {String} 给定的值
                 * @default 见源码
                 * @summary 设置组件查找页面选项元素的方法
                 */
                getEl: function (target, value) {
                    var index = _getRowIndex(target, value);
                    var id = $.data(target[0], _cacheName).itemIdPrefix + '_' + index;
                    return $('#' + id);
                },
                /**
                 * @type Function
                 * @name uiCombobox#finder.getRow
                 * @param target {jQuery} 组件对象
                 * @param p {String|jQuery} 给定的值|选项元素
                 * @default 见源码
                 * @summary 设置组件查找选项数据的方法
                 */
                getRow: function (target, p) {
                    var state = $.data(target[0], _cacheName);
                    var index = (p instanceof jQuery) ? p.attr('id').substr(state.itemIdPrefix.length + 1) : _getRowIndex(target, p);
                    if (index != undefined && index > -1) {
                        return state.data[parseInt(index)];
                    } else {
                        return undefined;
                    }
                }
            },
            onHidePanel: function () {
                var target = $(this);
                var opts = target.uiCombobox('options');
                if (opts.searchable && target.uiCombobox('getText') != "" && target.uiCombobox('getValues').length == 0) {
                    _setValues(target, [], false);
                }
            },

            /**
             * @summary 在组件数据加载前触发的方法。
             * @event
             * @name uiCombobox#onBeforeLoad
             * @param param {String} 数据请求的参数
             * @this 组件jQuery对象
             * @default emptyFn
             */
            onBeforeLoad: function (param) {
            },
            /**
             * @summary 在组件数据加载成功时触发的方法。
             * @event
             * @name uiCombobox#onLoadSuccess
             * @param data {Array<Object>} 所加载的数据列表
             * @this 组件jQuery对象
             * @default emptyFn
             */
            onLoadSuccess: function (data) {
            },
            /**
             * @summary 在组件数据加载失败时触发的方法。
             * @event
             * @name uiCombobox#onLoadError
             * @param param {String} 数据请求参数
             * @param success {Function} 数据请求成功执行的方法
             * @param error {Function} 数据请求失败执行的方法
             * @default emptyFn
             */
            onLoadError: function (param, success, error) {
            },
            /**
             * @summary 在组件选择选项时触发的方法。
             * @event
             * @name uiCombobox#onSelect
             * @param record {String} 所选择的数据对象
             * @this 组件jQuery对象
             * @default emptyFn
             */
            onSelect: function (record) {
            },
            /**
             * @summary 在组件取消选择选项时触发的方法。
             * @event
             * @name uiCombobox#onUnselect
             * @param record {String} 所选择的数据对象
             * @this 组件jQuery对象
             * @default emptyFn
             */
            onUnselect: function (record) {
            }
        });

    var _init = function (target) {
        var state = $.data(target[0], _cacheName);
        var opts = state.options;
        target.setElemID();
        var targetID = target.getElemID();
        state.itemIdPrefix = targetID + '_combobox_i';
        state.groupIdPrefix = targetID + '_combobox_g';
        if (target.attr('value')) {
            opts.value = target.attr('value');
        }
        target.uiCombo($.extend({}, opts, {
            onShowPanel: function () {
                target.uiCombo('panel').find('div.ui_combobox-item,div.ui_combobox-group').show();
                _scrollTo(target, target.uiCombobox('getValue'));
                opts.onShowPanel.call(target);
            }
        }));
        target.uiCombobox('panel').unbind().bind('mouseover', function (e) {
            $(this).children('div.ui_combobox-item-hover').removeClass('ui_combobox-item-hover');
            var item = $(e.target).closest('div.ui_combobox-item');
            if (!item.hasClass('ui_combobox-item-disabled')) {
                item.addClass('ui_combobox-item-hover');
            }
            e.stopPropagation();
        }).bind('mouseout', function (e) {
            $(e.target).closest('div.ui_combobox-item').removeClass('ui_combobox-item-hover');
            e.stopPropagation();
        }).bind('click', function (e) {
            var item = $(e.target).closest('div.ui_combobox-item');
            if (!item.length || item.hasClass('ui_combobox-item-disabled')) {
                return
            }
            var row = opts.finder.getRow(target, item);
            if (!row) {
                return
            }
            var value = row[opts.valueField];
            if (opts.multiple) {
                if (item.hasClass('ui_combobox-item-selected')) {
                    _unselect(target, value);
                } else {
                    _select(target, value);
                }
            } else {
                _select(target, value);
                target.uiCombo('hidePanel');
            }
            e.stopPropagation();
        });
    }

    var _getRowIndex = function (target, value) {
        if (value == undefined) {
            return -1;
        }
        var state = $.data(target[0], _cacheName);
        var opts = state.options;
        var data = state.data || [];
        for (var i = 0; i < data.length; i++) {
            if (data[i][opts.valueField] == value) {
                return i;
            }
        }
        return -1;
    }

    var _scrollTo = function (target, value) {
        var opts = $.data(target[0], _cacheName).options;
        var panel = target.uiCombo('panel');
        var item = opts.finder.getEl(target, value);
        if (item.length) {
            var h;
            if (item.position().top <= 0) {
                h = panel.scrollTop() + item.position().top;
            } else if (item.position().top + item.outerHeight() > panel.height()) {
                h = panel.scrollTop() + item.position().top + item.outerHeight() - panel.height();
            }
            panel.scrollTop(h);
        }
    }

    var _parseData = function (target) {
        var data = [];
        var opts = target.uiCombobox('options');
        target.children().each(function () {
            if (this.tagName.toLowerCase() == 'optgroup') {
                var group = $(this).attr('label');
                $(this).children().each(function () {
                    _parseItem(this, group);
                });
            } else {
                _parseItem(this);
            }
        });
        return data;

        function _parseItem(el, group) {
            var t = $(el);
            var row = {};
            row[opts.valueField] = t.attr('value') != undefined ? t.attr('value') : t.text();
            row[opts.textField] = t.text();
            if (opts.value == '') {
                row['selected'] = t.is(':selected');
            }
            row['disabled'] = t.is(':disabled');
            if (group) {
                opts.groupField = opts.groupField || 'group';
                row[opts.groupField] = group;
            }
            data.push(row);
        }
    };

    var _nav = function (target, dir) {
        var opts = $.data(target[0], _cacheName).options;
        var panel = target.uiCombobox('panel');
        var item = panel.children('div.ui_combobox-item-hover');
        if (!item.length) {
            item = panel.children('div.ui_combobox-item-selected');
        }
        item.removeClass('ui_combobox-item-hover');
        var firstSelector = 'div.ui_combobox-item:visible:not(.ui_combobox-item-disabled):first';
        var lastSelector = 'div.ui_combobox-item:visible:not(.ui_combobox-item-disabled):last';
        if (!item.length) {
            item = panel.children(dir == 'next' ? firstSelector : lastSelector);
        } else {
            if (dir == 'next') {
                item = item.nextAll(firstSelector);
                if (!item.length) {
                    item = panel.children(firstSelector);
                }
            } else {
                item = item.prevAll(firstSelector);
                if (!item.length) {
                    item = panel.children(lastSelector);
                }
            }
        }
        if (item.length) {
            item.addClass('ui_combobox-item-hover');
            var row = opts.finder.getRow(target, item);
            if (row) {
                _scrollTo(target, row[opts.valueField]);
                if (opts.selectOnNavigation) {
                    _select(target, row[opts.valueField]);
                }
            }
        }
    }

    var _select = function (target, value) {
        var opts = $.data(target[0], _cacheName).options;
        var values = target.uiCombo('getValues');
        if ($.inArray(value + '', values) == -1) {
            if (opts.multiple) {
                values.push(value);
            } else {
                values = [value];
            }
            _setValues(target, values);
            opts.onSelect.call(target, opts.finder.getRow(target, value));
        }
    }

    var _unselect = function (target, value) {
        var opts = $.data(target[0], _cacheName).options;
        var values = target.uiCombo('getValues');
        var index = $.inArray(value + '', values);
        if (index >= 0) {
            values.splice(index, 1);
            _setValues(target, values);
            opts.onUnselect.call(target, opts.finder.getRow(target, value));
        }
    }

    var _setValues = function (target, values, remainText) {
        var opts = $.data(target[0], _cacheName).options;
        var panel = target.uiCombo('panel');

        panel.find('div.ui_combobox-item-selected').removeClass('ui_combobox-item-selected');
        var vv = [], ss = [];
        if (opts.searchable) {
            for (var i = 0; i < values.length; i++) {
                var v = values[i];
                opts.finder.getEl(target, v).addClass('ui_combobox-item-selected');
                var row = opts.finder.getRow(target, v);
                if (row) {
                    s = row[opts.textField];
                    if (opts.searchable) {
                        ss.push($('<div>' + s + '</div>').text());
                        vv.push(v);
                    }
                }
            }
        } else {
            for (var i = 0; i < values.length; i++) {
                var v = values[i];
                var s = v;
                opts.finder.getEl(target, v).addClass('ui_combobox-item-selected');
                var row = opts.finder.getRow(target, v);
                if (row) {
                    s = row[opts.textField];
                }
                vv.push(v);
                ss.push($('<div>' + s + '</div>').text());
            }
        }
        target.uiCombo('setValues', vv);
        if (!remainText) {
            target.uiCombo('options').nullValue = opts.nullValue;
            target.uiCombo('setText', ss.join(opts.separator));
        }
        var comboText = target.uiCombo('textbox');
        comboText.attr('title', comboText.val());

    }

    var _loadData = function (target, data, remainText) {
        var state = $.data(target[0], _cacheName);
        var opts = state.options;
        state.data = opts.loadFilter.call(target, data);
        state.groups = [];
        data = state.data || [];

        var selected = target.uiCombobox('getValues');
        var dd = [];
        var group = undefined;
        for (var i = 0; i < data.length; i++) {
            var row = data[i];
            var v = row[opts.valueField] + '';
            var s = row[opts.textField];
            var g = row[opts.groupField];
            if (opts.nullValue && opts.nullValue == v) {
                opts.nullValue = s;
            }

            if (g) {
                if (group != g) {
                    group = g;
                    state.groups.push(g);
                    var text = opts.groupFormatter ? opts.groupFormatter.call(target, g) : g;
                    dd.push('<div title="' + text + '" id="' + (state.groupIdPrefix + '_' + (state.groups.length - 1)) + '" class="ui_combobox-group">');
                    dd.push(text);
                    dd.push('</div>');
                }
            } else {
                group = undefined;
            }

            var cls = 'ui_combobox-item' + (row.disabled ? ' ui_combobox-item-disabled' : '') + (g ? ' ui_combobox-gitem' : '');
            var rowText = opts.formatter ? opts.formatter.call(target, row) : s;
            var title = $('<div>' + rowText + '</div>').text();
            dd.push('<div title="' + title + '" id="' + (state.itemIdPrefix + '_' + i) + '" class="' + cls + '">');
            dd.push(rowText);
            dd.push('</div>');
            if (row['selected'] && $.inArray(v, selected) == -1) {
                selected.push(v);
            }
        }
        var comboPal = target.uiCombo('panel');
        comboPal.addClass('overflowY');
        comboPal.html(dd.join(''));

        if (opts.multiple) {
            _setValues(target, selected, remainText);
        } else {
            _setValues(target, selected.length > 0 ? [selected[selected.length - 1]] : [], remainText);
        }
        opts.onLoadSuccess.call(target, data);
    }

    var _request = function (target, url, param, remainText) {
        var opts = $.data(target[0], _cacheName).options;
        if (url) {
            opts.url = url;
        }
        param = param || {};

        if (opts.onBeforeLoad.call(target, param) == false) return;

        opts.loader.call(target, param, function (data) {
            _loadData(target, data, remainText);
        }, function () {
            opts.onLoadError.apply(this, arguments);
        });
    }

    var _doQuery = function (target, input) {
        var state = $.data(target[0], _cacheName);
        var opts = state.options;
        if (opts.multiple && !input) {
            _setValues(target, [], true);
        } else {
            _setValues(target, [input], true);
        }

        if (opts.mode == 'remote') {
            var mi = opts.queryMin;
            if (typeof mi == "number") {
                if ($.trim(input).length >= mi) {
                    _request(target, null, {input: input}, true);
                }
            }
            if (typeof mi == "object") {
                if (!isChinese(input) && $.trim(input).length >= mi[0]) {
                    _request(target, null, {input: input}, true);
                }
                if (isChinese(input) && $.trim(input).length >= mi[1]) {
                    _request(target, null, {input: input}, true);
                }
            }
        } else {
            var panel = target.uiCombo('panel');
            panel.find('div.ui_combobox-item-selected,div.ui_combobox-item-hover').removeClass('ui_combobox-item-selected ui_combobox-item-hover');
            panel.find('div.ui_combobox-item,div.ui_combobox-group').hide();
            var data = state.data;
            var vv = [];
            var qq = opts.multiple ? input.split(opts.separator) : [input];
            var isOnlyOne = false;
            $.map(qq, function (q) {
                q = $.trim(q);
                var group = undefined;
                for (var i = 0; i < data.length; i++) {
                    var row = data[i];
                    if (opts.filter.call(target, q, row)) {
                        var v = row[opts.valueField];
                        var s = row[opts.textField];
                        var g = row[opts.groupField];
                        var item = opts.finder.getEl(target, v).show();
                        if (item) {
                            vv.push(v);
                            st = $('<div>' + s + '</div>').text();
                            if (st.toLowerCase() == q.toLowerCase()) {
                                isOnlyOne = true;
                            }
                        }
                        if (opts.groupField && group != g) {
                            $('#' + state.groupIdPrefix + '_' + $.inArray(g, state.groups)).show();
                            group = g;
                        }
                    }
                }
            });
            if (vv.length == 1 && isOnlyOne) {
                _select(target, vv[0]);
                target.uiCombobox('hidePanel');
            }
        }
    }

    var _doEnter = function (target) {
        var opts = target.uiCombobox('options');
        var panel = target.uiCombobox('panel');
        var item = panel.children('div.ui_combobox-item-hover');
        if (item.length) {
            var row = opts.finder.getRow(target, item);
            var value = row[opts.valueField];
            if (opts.multiple) {
                if (item.hasClass('ui_combobox-item-selected')) {
                    target.uiCombobox('unselect', value);
                } else {
                    target.uiCombobox('select', value);
                }
            } else {
                target.uiCombobox('select', value);
            }
        }
        var vv = [];
        $.map(target.uiCombobox('getValues'), function (v) {
            if (_getRowIndex(target, v) >= 0) {
                vv.push(v);
            }
        });
        target.uiCombobox('setValues', vv);
        if (!opts.multiple) {
            target.uiCombobox('hidePanel');
        }
    }
})(jQuery);